#ifndef STORE_H_
#define STORE_H_

#include <iterator>
#include <string>
#include <iostream>
#include <stdexcept>

#include <leveldb/db.h>
#include <protocol/TBinaryProtocol.h>
#include <transport/TBufferTransports.h>
#include <bloom/bloom_filter.hpp>

#include "thrift/CrawlerServer.h"
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using boost::shared_ptr;

namespace crawler { namespace server {
class Iterator : std::iterator<std::forward_iterator_tag, Page> {
 public:
  Iterator() : end_(true) {}
  Iterator(const boost::shared_ptr<leveldb::Iterator> &db_iter) :
    db_iter_(db_iter),
    mem_buf_(new TMemoryBuffer),
    bin_proto_(new TBinaryProtocol(mem_buf_)),
    end_(false) {
    db_iter_->SeekToFirst();
    PrepareValue();
  }
  Iterator(const Iterator& it) :
    db_iter_(it.db_iter_),
    mem_buf_(new TMemoryBuffer),
    bin_proto_(new TBinaryProtocol(mem_buf_)),
    end_(false) {}
  Iterator& operator++() {
    db_iter_->Next();
    PrepareValue();
    return *this;
  }
  Iterator operator++(int) {
    Iterator tmp(*this);
    operator++();
    return tmp;
  }
  bool operator==(const Iterator& rhs) const {
    if (rhs.end_) {
      return end_;
    } else if (!db_iter_->Valid()) {
      return !rhs.db_iter_->Valid();
    } else if (db_iter_->Valid() && rhs.db_iter_->Valid()) {
      return operator*() == *rhs;
    } else {
      return false;
    }
  }
  bool operator!=(const Iterator& rhs) const {
    return !(*this == rhs);
  }
  const Page& operator*() const {
    return page_;
  }
  const Page* operator->() const {
    return &page_;
  }

 private:
  void PrepareValue() {
    if (db_iter_->Valid()) {
      page_.~Page();
      new (&page_)Page;
      mem_buf_->resetBuffer((uint8_t*)db_iter_->value().data(), db_iter_->value().size());
      page_.read(bin_proto_.get());
    } else {
      end_ = true;
      if (!db_iter_->status().ok()) {
        throw std::runtime_error(db_iter_->status().ToString());
      }
    }
  }

  shared_ptr<leveldb::Iterator>   db_iter_;
  Page                            page_;
  shared_ptr<TMemoryBuffer>       mem_buf_;
  shared_ptr<TBinaryProtocol>     bin_proto_;
  bool                            end_;
};
class Store {
 public:
  typedef Iterator PageIterator;
  Store(const std::string &store_db_path);
  void StorePage(const Page &page);
  void StoreLink(const Link &link);
  void GetPage(const std::string &url, Page &page);
  PageIterator Begin() const;
  const PageIterator &End() const;

 private:
  std::string                            store_db_path_;
  boost::shared_ptr<leveldb::DB>         db_;
  boost::shared_ptr<leveldb::Iterator>   db_iter_;
  boost::shared_ptr<bloom_filter>        found_links_filter_;
  PageIterator                           end_iter_;  
};
}}

#endif // STORE_H_

